package plot
{
	import mx.collections.ArrayCollection;
	import mx.core.UIComponent;
	import mx.controls.Label;
	import mx.managers.CursorManager;
	
	public class ParallelSeries extends UIComponent
	{
		//---------------------------------------------------------------------
        //
        // Properties
        //
        //---------------------------------------------------------------------
        
		public var lineThickness:int = 2;
		public var color:uint = 0x000000;
		public var selectedColor:uint = 0x000000;
		public var opacity:Number = 0.5;
		
		[Bindable]
		/**
		 * should go in teh order of appearance
		 */
		public var axes:ArrayCollection; /* of Strings*/
		
		[Bindable]
		/**
		 * selected Items
		 */
		public var selectedItems:ArrayCollection; /* of dataItems */
		
		[Bindable]
		/**
		 * should have all the same axes as <code>axes</code> variable
		 */
		public var data:ArrayCollection; /* of ArrayCollection */
		
		[Bindable]
		public function get dataProvider():ArrayCollection
		{
			return _dataProvider;
		}
		public function set dataProvider(value:ArrayCollection):void
		{
			_dataProvider = value;
			
			_processedData = preprocessCustomDataTypes();
			_scaledData = calculateScaleIndex();
			invalidateDisplayList();
		}
		private var _dataProvider:ArrayCollection;
		/**
		 * All categorical values are substituted with numbers, ordered.
		 */
		private var _processedData:ArrayCollection;
		/**
		 * Normalized by min/max values, width and height of the component.
		 */
		private var _scaledData:ArrayCollection;
		
		[Bindable]
		internal var minimumValues:Array = [];
		
		[Bindable]
		internal var maximumValues:Array = [];
		
		private var column_count:int = 0;
		
		
		
		//---------------------------------------------------------------------
        //
        // Methods
        //
        //---------------------------------------------------------------------
		
		/**
		 * Constructor
		 */
		public function ParallelSeries()
		{
			// do something very good here
		}
		
		/**
		 * Rendering
		 */
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
		{
			graphics.clear();
			
			var colWidth:int = unscaledWidth / (axes.length - 1);
			var x:int;
			
			graphics.lineStyle(lineThickness, color, opacity);
//			graphics.beginFill(color, opacity);

			for (var i:int = 0; i < _processedData.length; i++)
			{
				x = 0;
				graphics.moveTo(x, _processedData[i][0]);
				for (var j:int; j < _processedData[i].length - 1; j++)
				{
					x += colWidth;
					graphics.lineTo(x, _processedData[i][j + 1]);
						
				}
			}
			graphics.endFill();
		}
		
		/**
        * Organizes categorical data and dates (sorts them, assigns
        * numerical values for later scaling) 
        */
        private function preprocessCustomDataTypes():ArrayCollection
        {
        	trace("processing " + new Date().toString());
        	
        	CursorManager.setBusyCursor();
        	// add all columns that contain Strings or Dates
        	var customDataIndex:ArrayCollection = new ArrayCollection();
        	var dictionary:Array = new Array();
        	var map:Object;
        	var label:String;
        	var j:int;
        	
        	min = new Array();
        	max = new Array();
        	
        	for (var i:int = 0; i < column_count; i++)
        	{
        		label = labels[i];
        		max[label] = dataProvider[0][label];
	        	min[label] = dataProvider[0][label];
        		
        		/// if date
        		if (dataProvider[0][label] is Date )
        		{
        			customDataIndex.addItem(label);
        			dictionary[label] = {};
        			// go through all rows in this column and add all of the unique values to the map
        			for (j = 0; j < row_count; j++)
        			{
        				map = dictionary[label];
        				map[dataProvider[j][label]] = dataProvider[j][label];
        			}
        			dictionary[label] = Utils.sortMap(dictionary[label], Date);
        		}
        		// if string
        		else if (dataProvider[0][label] is String)
        		{
        			customDataIndex.addItem(label);
        			dictionary[label] = {};
        			// go through all rows in this column and add all of the unique values to the map
        			for (j = 0; j < row_count; j++)
        			{
        				map = dictionary[label];
        				map[dataProvider[j][label]] = dataProvider[j][label];
        			}
        			dictionary[label] = Utils.sortMap(dictionary[label], String);
        		}
        	}
        		
        	var new_data:ArrayCollection = new ArrayCollection();
        	for (i = 0; i < row_count; i++)
        	{
        		new_data.addItem( new Array());
        	}
        	
    		var _min:Object;
    		var _max:Object;
    		// copy data for the number columns
    		for (j = 0; j < column_count; j++)
    		{
    			label = labels[j];
    			_min = min[label];
    			_max = max[label];
    		
    			if (!customDataIndex.contains(labels[j]))
    				for (i = 0; i < row_count; i++)
    				{
    					new_data[i][label] = dataProvider[i][label];
    				
    				if (dataProvider[i][label] < _min) 
        				_min = dataProvider[i][label];
        			if (dataProvider[i][label] > _max)
        				_max = dataProvider[i][label];
    			}
        		min[label] = _min;
        		max[label] = _max;
        	}
        			
        	// substitute values with numbers
        	for (j = 0; j < customDataIndex.length; j++)
        	{
        		label = customDataIndex[j];
        		map = dictionary[label];
        		_min = min[label] = map[dataProvider[j][label]];
        		_max = max[label] = map[dataProvider[j][label]]
        		
        		for (i = 0; i < row_count; i++){
        			var value:String = dataProvider[i][label].toString();
        			new_data[i][label] = map[value];
        			
        			if (new_data[i][label] < _min) 
	        			_min = new_data[i][label];
	        		if (new_data[i][label] > _max)
	        			_max = new_data[i][label];
        		}
        		min[label] = _min;
        		max[label] = _max;
        			
        	}
        	CursorManager.removeBusyCursor();
        	return new_data;
        }
		
		private function calculateScaleIndex():ArrayCollection
        {
        	trace("scaling " + new Date().toString());
        	// TODO: fill out
        	var scaledData:ArrayCollection;
        	

        	scaleIndex = new Array();
        	var label:String;
        	
        	for (var i:int = 0; i < column_count ; i++)
        	{
        		label = labels[i];
        		if (max[label] - min[label] == 0)
        			if (max[label] == 0)	// all values are 0's
        				scaleIndex[i] = (this.height - 2 * borderY );
        			else
        				scaleIndex[i] = (this.height - 2 * borderY)/max[label];	// scale down
        		else 
        			scaleIndex[i] = (this.height - 2 * borderY) /(max[label] - min[label]);
        	}
        	
        	return scaledData;
        }

	}
}
